import java.util.ArrayList;
import java.util.List;

public class Ant {
	private Tile position;

	private List<Tile> route;

	private Tile target;
	
	private AntState state;
	
	private Ants worldState;
	
	private int cantMoves;
	
	private Ant engager;
	
	private List<Ant> followers = new ArrayList<Ant>();
	
	private static final int GET_FUCKING_OFF_TIMEOUT = 2;

	private static final int RESET_TIMEOUT = 4;
	
	public Ant (Tile position, Ants worldState) {
		this.position = position;
		this.state = AntState.IDLE;
		route = new ArrayList<Tile>();
		cantMoves = 0;
		this.worldState = worldState;
		worldState.getMyAntsPositions()[position.getRow()][position.getCol()] = this;
	}

	public Tile getPosition() {
		return position;
	}

	public void setPosition(Tile newPosition) {
		if (route != null && !route.isEmpty()) {
			 if(route.get(0).equals(newPosition))
				route.remove(0);
		}
			
		worldState.getMyAntsPositions()[position.getRow()][position.getCol()] = null;
		this.position = newPosition;
		worldState.getMyAntsPositions()[position.getRow()][position.getCol()] = this;
	}

	public Tile getTarget() {
		return target;
	}
	
	public Tile getNextPosition() {
		if (route == null || route.isEmpty())
			return null;
		
		if (!worldState.getIlk(route.get(0)).isPassable())
			route = PathFind.getSingleton().findPath(worldState, position, target);
		
		if (route == null || route.isEmpty())
			return null;
		
		if (worldState.getIlk(route.get(0)) == Ilk.MY_ANT) {
			++cantMoves;
			return null;
		}
		
		cantMoves = 0;
		
		return route.get(0);
	}

	public void setTarget(Tile target) {
		route = PathFind.getSingleton().findPath(worldState, position, target);
		
		if (route == null)
			state = AntState.IDLE;
			
		this.target = target;
	}

	public List<Tile> getRoute() {
		return route;
	}

	public void setRoute(List<Tile> route) {
		this.route = route;
	}

	public AntState getState() {
		return state;
	}

	public void setState(AntState newState) {
		if (this.state == AntState.FOLLOWING)
			engager.notifyStopFollowing(this);
		
		this.state = newState;
	}
	
	public void resetState() {
		state = AntState.IDLE;
		route = null;
		target = null;
		engager = null;
		for (Ant follower : followers) {
			follower.resetState();
		}
		followers.clear();
	}
	
	public void notifyStartFollowing(Ant follower) {
		followers.add(follower);
	}
	
	public void notifyStopFollowing(Ant follower) {
		followers.remove(follower);
	}
	
	private boolean needToFuckOff() {
		if (state != AntState.IDLE)
			return false;
		
		for (Aim direction : Aim.values()) {
			Tile tile = worldState.getTile(position, direction);
			
			if (worldState.getMyAntsPositions()[tile.getRow()][tile.getCol()].getNextPosition().equals(position))
				return true;
		}
		
		return false;
	}
	
	private void getFuckingOff() {
		Aim mainDirection = worldState.getDirections(position, route.get(0)).get(0);
		if (mainDirection == Aim.NORTH || mainDirection == Aim.SOUTH) {
			if (worldState.getIlk(worldState.getTile(position, Aim.WEST)).isUnoccupied()) {
				route.add(0, worldState.getTile(position, Aim.WEST));
				if (state != AntState.IDLE) {
					route.add(1, position);
				}
				cantMoves = 0;
			}
			else if (worldState.getIlk(worldState.getTile(position, Aim.EAST)).isUnoccupied()) {
				route.add(0, worldState.getTile(position, Aim.EAST));
				if (state != AntState.IDLE) {
					route.add(1, position);
				}
				cantMoves = 0;
			}
		}
		else {
			if (worldState.getIlk(worldState.getTile(position, Aim.NORTH)).isUnoccupied()) {
				route.add(0, worldState.getTile(position, Aim.NORTH));
				if (state != AntState.IDLE) {
					route.add(1, position);
				}
				cantMoves = 0;
			}
			else if (worldState.getIlk(worldState.getTile(position, Aim.SOUTH)).isUnoccupied()) {
				route.add(0, worldState.getTile(position, Aim.SOUTH));
				if (state != AntState.IDLE) {
					route.add(1, position);
				}
				cantMoves = 0;
			}
		}
	}
	
	public void update(Ants worldState) {
		this.worldState = worldState;
		
		if (target == null || route == null || route.isEmpty()) {
			resetState();
			return;
		}
		
		if (needToFuckOff())
			getFuckingOff();
		
		if (cantMoves > GET_FUCKING_OFF_TIMEOUT && position.compareTo(route.get(0)) > 0)
			getFuckingOff();
		
		if (cantMoves > RESET_TIMEOUT)
			resetState();
		
		if (state == AntState.GATHERING_FOOD && worldState.getIlk(target) != Ilk.FOOD) {
			resetState();
			return;
		}
		
		if (state == AntState.RAZING && !worldState.getEnemyHills().contains(target)) {
			resetState();
			return;
		}
		
		if (state == AntState.EXPLORING && (position.equals(target) || !worldState.getIlk(target).isPassable())) {
			resetState();
			return;
		}
	}

	public void mimic(Ant otherAnt) {
		engager = otherAnt;
		otherAnt.notifyStartFollowing(this);
		setState(AntState.FOLLOWING);
		setTarget(otherAnt.getTarget());
	}
}
